﻿using Microsoft.CodeAnalysis;
using Microsoft.Win32;
using System.IO;
using System.Reflection;
using System.Windows;


namespace AiMoWindows.Compiler
{
    static class ReferenceAssemblis
    {

        public static MetadataReference[] DefaultAssemblies
        {
            get
            {
                HashSet<MetadataReference> assemblies = new HashSet<MetadataReference>();
                assemblies.UnionWith(ExternalRhinoAssembles.Select(CreateMetadataReference));
                assemblies.UnionWith(Net48Assemblies.Select(CreateMetadataReference));
                return assemblies.ToArray();
            }
        }

        public static MetadataReference CreateMetadataReference(string path)
        {
            return MetadataReference.CreateFromFile(path, MetadataReferenceProperties.Assembly, DocumentationProvider.Default);
        }

        public static void SetExternalAssemblyLocations(string[] externalLocations)
        {
            ExternalRhinoAssembles = externalLocations.Where(x => (!string.IsNullOrEmpty(x)) && File.Exists(x)).ToArray();
        }
        static string[] ExternalRhinoAssembles = Array.Empty<string>();
        static readonly string[] Net48Assemblies = GetSystemNet48AssembliesLocations();

        static string[] GetSystemNet48AssembliesLocations()
        {
            HashSet<Assembly> assemblies = new HashSet<Assembly>();
            try
            {
                RegistryKey? key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\.NETFramework")
                    ?? throw new Exception("Cannot Get Net Framework Installed Path");
                string path = key.GetValue("InstallRoot") as string ?? "";
                if (string.IsNullOrEmpty(path)) throw new Exception("Cannot Get Net Framework Installed Path");

                DirectoryInfo frameworkDirectory = new DirectoryInfo(path);
                if (frameworkDirectory == null || !frameworkDirectory.Exists) throw new Exception("Cannot Get Net Framework Installed Path");

                FileInfo[] mscorlibInfos = frameworkDirectory.GetFiles("*mscorlib.dll", SearchOption.AllDirectories);
                if (mscorlibInfos.Length == 0) throw new Exception($"Cannot Get mscorlib.dll in {frameworkDirectory.FullName}");

                // mscorlibInfo: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\mscorlib.dll
                FileInfo mscorlibInfo = mscorlibInfos.FirstOrDefault(x => x.FullName.Contains("v4")) ?? mscorlibInfos[0];

                // mscorlibDirectoryInfo: C:\Windows\Microsoft.NET\Framework64\v4.0.30319
                DirectoryInfo mscorlibDirectoryInfo = mscorlibInfo.Directory ?? throw new Exception($"Cannot get directory of mscorlib {mscorlibInfo.FullName}");


                string[] locations = new string[]
                {
                    // "C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.dll"
                    mscorlibInfo.FullName,
                    Path.Combine(mscorlibDirectoryInfo.FullName, "System.Core.dll"),
                    Path.Combine(mscorlibDirectoryInfo.FullName, "System.Data.dll"),
                    Path.Combine(mscorlibDirectoryInfo.FullName, "System.dll"),
                    Path.Combine(mscorlibDirectoryInfo.FullName, "System.Drawing.dll"),
                    Path.Combine(mscorlibDirectoryInfo.FullName, "System.IO.Compression.FileSystem.dll"),
                    Path.Combine(mscorlibDirectoryInfo.FullName, "System.Windows.Forms.dll"),
                    Path.Combine(mscorlibDirectoryInfo.FullName, "System.Numerics.dll"),
                    Path.Combine(mscorlibDirectoryInfo.FullName, "System.Runtime.Serialization.dll"),
                    Path.Combine(mscorlibDirectoryInfo.FullName, "System.XML.dll"),
                    Path.Combine(mscorlibDirectoryInfo.FullName, "System.Xml.Linq.dll"),
                    Path.Combine(mscorlibDirectoryInfo.FullName, "netstandard.dll"),
                };
                return locations.Where(File.Exists).ToArray();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Cannot Get Net Framework Assemblies\n" + ex, "Error");
                return Array.Empty<string>();
            }
        }
    }
}
